package neuronalenetzeelearning.model;

import java.util.Vector;

// <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
// #[regen=yes,id=DCE.33BD75D4-FB98-867B-23BD-39B675B73763]
// </editor-fold> 
public abstract class Node implements INode {

    public static final double DEFAULT_THRESHOLD = 0;
    public static final double DEFAULT_OUTPUT_VALUE = 0;
    private Vector<Edge> edges;
    private double threshold;
    private double outputValue;
    private String name;
    private double input;

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.3EA2005D-DB87-3B47-1D06-0B1F4E86E343]
    // </editor-fold> 
    public Node() {
        this("new Node");
    }

    public Node(String name) {
        this.name = name;
        edges = new Vector<Edge>();
        threshold = DEFAULT_THRESHOLD;
        outputValue = DEFAULT_OUTPUT_VALUE;
    }

    public void addConnectedEdge(Edge edge) {
        //Adding an edge should be called via graph
        this.edges.add(edge);
    }

    //Deleting the edges should be supervised in the graph
    /*
    public void deleteEdge (Edge edge){

    }*/
    /**
     * Gibt einen Knoten zurück, der mit diesem Knoten über die angegebene Kante verbunden ist
     * @param edge Kante, über die beide Knoten verbunden sind
     * @return Knoten, der über Kante edge mit diesem Knoten verbunden ist
     */
    public INode getOtherNodeConnectedVia(Edge edge) {
        INode otherNode = null;
        if (this == edge.getFrom()) {
            otherNode = edge.getTo();
        } else {
            otherNode = edge.getFrom();
        }
        return otherNode;
    }

    @Override
    public Vector<Edge> getIncomingEdges() {
        Vector<Edge> incoming = new Vector<Edge>();
        if (edges != null) {
            int size = edges.size();
            for (int i = 0; i < size; i++) {
                if (edges.elementAt(i).getTo() == this) {
                    incoming.add(edges.elementAt(i));
                }
            }
        }
        return incoming;
    }

    @Override
    public double getOutputValue() {
        return outputValue;
    }

    @Override
    public Vector<Edge> getEdges() {
        return edges;
    }

    @Override
    public Vector<Edge> getOutgoingEdges() {
        Vector<Edge> outgoing = new Vector<Edge>();
        if (this.edges != null) {
            int size = edges.size();
            for (int i = 0; i < size; i++) {
                if (edges.elementAt(i).getFrom() == this) {
                    outgoing.add(edges.elementAt(i));
                }
            }
        }
        return outgoing;
    }

    @Override
    public double getThreshold() {
        return threshold;
    }

    @Override
    public void setEdges(Vector<Edge> edges) {
        this.edges = edges;
    }

    @Override
    public void setOutputValue(double outputValue) {
        this.outputValue = outputValue;
    }

    @Override
    public void setThreshold(double threshold) {
        this.threshold = threshold;
    }

    public void setInputValue(double input){
       this.input=input;
    }

    public double getInputValue(){
        return input;
    }
    /**
     * Summiert die Werte, die in einen Knoten hineingehen.
     * @return Summe der in einen Knoten eingehenden Werte
     */

    @Override
    public double nettoinput() {
        double nettoinput = 0.0;
        Vector<Edge> incomming = this.getIncomingEdges();
        if (this instanceof Layer1Node) {
           //NI muss die entsprechende Komponente im InputVector sein
            nettoinput = getInputValue();
        } else {
            for (int i = 0; i < incomming.size(); i++) {
                double nodeOutput = this.getOtherNodeConnectedVia(incomming.elementAt(i)).getOutputValue();
                //getOutputValue hängt jetzt von der Wahl der Aktivierungsfkt ab
                nettoinput += nodeOutput * incomming.elementAt(i).getWeight();
            }
        }
        return nettoinput;
    }
    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.236AD1B7-005A-EDF3-3C75-0AF7DEBFA6BA]
    // </editor-fold>

    /**
     * Summiert die Werte, die in einen Knoten hineingehen.
     * @return Summe der in einen Knoten eingehenden Werte
     */


    @Override
    public String toString() {
        return "[" + this.name + "," + this.getThreshold() + "]";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

